/*
 * Copyright (c) 2019. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
 * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
 * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
 * Vestibulum commodo. Ut rhoncus gravida arcu.
 */

package com.darly.dlcommon.common.bolts.tasks;

import java.util.Locale;
import java.util.concurrent.CancellationException;

/**
 * Propagates notification that operations should be canceled.
 * <p/>
 * Create an instance of {@code CancellationTokenSource} and pass the token returned from
 * {@code CancellationTokenSource#getToken()} to the asynchronous operation(s).
 * Call {@code CancellationTokenSource#cancel()} to cancel the operations.
 * <p/>
 * A {@code CancellationToken} can only be cancelled once - it should not be passed to future operations
 * once cancelled.
 *
 * @see CancellationTokenSource
 * @see CancellationTokenSource#getToken()
 * @see CancellationTokenSource#cancel()
 * @see CancellationToken#register(Runnable)
 */
public class CancellationToken {

    private final CancellationTokenSource tokenSource;

    /* package */ CancellationToken(CancellationTokenSource tokenSource) {
        this.tokenSource = tokenSource;
    }

    /**
     * @return {@code true} if the cancellation was requested from the source, {@code false} otherwise.
     */
    public boolean isCancellationRequested() {
        return tokenSource.isCancellationRequested();
    }

    /**
     * Registers a runnable that will be called when this CancellationToken is canceled.
     * If this token is already in the canceled state, the runnable will be run immediately and synchronously.
     *
     * @param action the runnable to be run when the token is cancelled.
     * @return a {@link CancellationTokenRegistration} instance that can be used to unregister
     * the action.
     */
    public CancellationTokenRegistration register(Runnable action) {
        return tokenSource.register(action);
    }

    /**
     * @throws CancellationException if this token has had cancellation requested.
     *                               May be used to stop execution of a thread or runnable.
     */
    public void throwIfCancellationRequested() throws CancellationException {
        tokenSource.throwIfCancellationRequested();
    }

    @Override
    public String toString() {
        return String.format(Locale.US, "%s@%s[cancellationRequested=%s]",
                getClass().getName(),
                Integer.toHexString(hashCode()),
                Boolean.toString(tokenSource.isCancellationRequested()));
    }
}
